﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Labthink.PCSoft.UniversalHost4.Utility
{
    public class IniHelper
    {
        public static string Filename { get; set; }

        public static string SectionName { get; set; }

        #region 公共方法
        /// <summary>
        /// 读取配置文件
        /// </summary>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="defaultValue">传""</param>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string GetIni(string filePath, string section, string key, string defaultValue)
        {
            return IniCommon(true, section, key, defaultValue, filePath);
        }

        /// <summary>
        /// 读取配置文件
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultValue">传""</param>
        /// <returns></returns>
        public static string GetIni(string key, string defaultValue)
        {
            return IniCommon(true, SectionName, key, defaultValue, Filename);
        }

        /// <summary>
        /// 设置配置文件
        /// </summary>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string SetIni(string filePath, string section, string key, string value)
        {
            return IniCommon(false, section, key, value, filePath);
        }

        /// <summary>
        /// 设置配置文件
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string SetIni(string key, string value)
        {
            return IniCommon(false, SectionName, key, value, Filename);
        }

        public static void SetIni(string fileName, List<IniData> datas)
        {
            string section = "";
            string strBuf;
            try
            {
                //a.文件不存在则创建
                if (!File.Exists(fileName))
                {
                    FileStream sr = File.Create(fileName);
                    sr.Close();
                }

                //读取INI文件
                var stream = new StreamReader(fileName, Encoding.Default);
                strBuf = stream.ReadToEnd();//读取ini文件
                stream.Close();
            }
            catch
            {
                return;
            }

            List<IniData> tmpDatas = null;
            string[] rows = Split(strBuf, "\r\n");
            int i = 0;
            for (; i < rows.Length; i++)
            {
                string oneRow = rows[i].Trim();

                //空行
                if (0 == oneRow.Length)
                    continue;

                //此行为注释
                if (';' == oneRow[0])
                    continue;

                if ('[' == oneRow[0] && oneRow[oneRow.Length - 1] == ']')
                {
                    if (section != "")
                    {
                        datas.RemoveAll(ini =>
                        {
                            if (ini.SectionName == section)
                            {
                                return true;
                            }
                            return false;
                        });
                    }
                    section = oneRow.Replace("[", "").Replace("]", "");
                    tmpDatas = datas.Where(ini => ini.SectionName == section).ToList();
                }
                else
                {
                    if (tmpDatas != null && tmpDatas.Count > 0)
                    {
                        string[] kv = oneRow.Split('=');
                        IniData data = tmpDatas.FirstOrDefault(ini => ini.KeyName == kv[0]);
                        if (data != null)
                        {
                            rows[i] = data.KeyName + "=" + data.KeyValue;
                        }
                    }
                }
            }

            WriteArray(fileName, rows);
            if (section != "")
            {
                datas.RemoveAll(ini =>
                {
                    if (ini.SectionName == section)
                    {
                        return true;
                    }
                    return false;
                });
            }

            List<string> tmpIni = new List<string>();
            if (datas != null && datas.Count > 0)
            {
                foreach (IniData id in datas.OrderBy(ini => ini.SectionName))
                {
                    section = "[" + id.SectionName + "]";
                    if (!tmpIni.Contains(section))
                    {
                        tmpIni.Add(section);
                    }
                    tmpIni.Add(id.KeyName + "=" + id.KeyValue);
                }
            }
            if (tmpIni.Count > 1)
            {
                AppendToFile(fileName, tmpIni.ToArray());
            }
        }

        /// <summary>
        /// 获取全部配置项
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static List<IniData> GetIni(string fileName)
        {
            List<IniData> data = new List<IniData>();
            string section = "";
            string strBuf;
            try
            {
                if (!File.Exists(fileName))
                {
                    return data;
                }

                //读取INI文件
                var stream = new StreamReader(fileName, Encoding.Default);
                strBuf = stream.ReadToEnd();//读取ini文件
                stream.Close();
            }
            catch
            {
                return data;
            }

            string[] rows = Split(strBuf, "\r\n");
            int i = 0;
            for (; i < rows.Length; i++)
            {
                string oneRow = rows[i].Trim();

                //空行
                if (0 == oneRow.Length)
                    continue;

                //此行为注释
                if (';' == oneRow[0])
                    continue;

                if ('[' == oneRow[0] && oneRow[oneRow.Length - 1] == ']')
                {
                    section = oneRow.Replace("[", "").Replace("]", "");
                }
                else
                {
                    var d= new IniData();
                    d.SectionName = section;
                    string[] kv = oneRow.Split('=');
                    d.KeyName = kv[0].Trim();
                    d.KeyValue = kv[1];
                    data.Add(d);
                }
            }

            return data;
        }

        /// <summary>
        /// 批量获取配置文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="datas"></param>
        public static void GetIni(string fileName, List<IniData> datas)
        {
            string section;
            string strBuf;
            try
            {
                if (!File.Exists(fileName))
                {
                    return;
                }

                //读取INI文件
                var stream = new StreamReader(fileName, Encoding.Default);
                strBuf = stream.ReadToEnd();//读取ini文件
                stream.Close();
            }
            catch
            {
                return;
            }

            List<IniData> tmpDatas = null;
            string[] rows = Split(strBuf, "\r\n");
            int i = 0;
            for (; i < rows.Length; i++)
            {
                string oneRow = rows[i].Trim();

                //空行
                if (0 == oneRow.Length)
                    continue;

                //此行为注释
                if (';' == oneRow[0])
                    continue;

                if ('[' == oneRow[0] && oneRow[oneRow.Length - 1] == ']')
                {
                    section = oneRow.Replace("[", "").Replace("]", "");
                    tmpDatas = datas.Where(ini => ini.SectionName == section).ToList();
                }
                else
                {
                    if (tmpDatas != null && tmpDatas.Count > 0)
                    {
                        string[] kv = oneRow.Split('=');
                        IniData data = tmpDatas.FirstOrDefault(ini => ini.KeyName == kv[0]);
                        if (data != null)
                        {
                            data.KeyValue = kv[1];
                        }
                    }
                }
            }

        }

        /// <summary>
        /// 获取单个配置文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="data"></param>
        public static void GetIni(string fileName, IniData data)
        {
            data.KeyValue = IniCommon(false, data.SectionName, data.KeyName, data.KeyValue, fileName);
        }
        #endregion

        #region 内部方法
        /// <summary>
        /// 拆分字符串
        /// </summary>
        /// <param name="input"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        private static string[] Split(string input, string pattern)
        {
            string[] arr = System.Text.RegularExpressions.Regex.Split(input, pattern);
            return arr;
        }

        private static string[] Split1(string input, string pattern)
        {
            string[] arr = System.Text.RegularExpressions.Regex.Split(input, pattern);
            if (arr.Length <= 2) return arr;
            int index = input.IndexOf(pattern, StringComparison.Ordinal);
            return new[] { input.Substring(0, index), input.Substring(index + 1) };
        }

        /// <summary>
        /// 写数据到文件
        /// </summary>
        /// <param name="strPath"></param>
        /// <param name="strContent"></param>
        private static void AppendToFile(string strPath, string strContent)
        {
            var fs = new FileStream(strPath, FileMode.Append);
            var streamWriter = new StreamWriter(fs, Encoding.Default);
            streamWriter.BaseStream.Seek(0, SeekOrigin.End);
            streamWriter.WriteLine(strContent);
            streamWriter.Flush();
            streamWriter.Close();
            fs.Close();
        }

        private static void AppendToFile(string strPath, string[] strContent)
        {
            var fs = new FileStream(strPath, FileMode.Append);
            var streamWriter = new StreamWriter(fs, Encoding.Default);
            streamWriter.BaseStream.Seek(0, SeekOrigin.End);
            for (int i = 0; i < strContent.Length; i++)
            {
                if (strContent[i].Trim() == "\r\n")
                    continue;

                if (strContent[i].Trim() == "")
                    continue;

                streamWriter.WriteLine(strContent[i].Trim());
            }

            streamWriter.Flush();
            streamWriter.Close();
            fs.Close();
        }

        /// <summary>
        /// 写数据到文件
        /// </summary>
        /// <param name="strPath"></param>
        /// <param name="strContent"></param>
        private static void WriteArray(string strPath, string[] strContent)
        {
            var fs = new FileStream(strPath, FileMode.Truncate);
            var streamWriter = new StreamWriter(fs, Encoding.Default);
            streamWriter.BaseStream.Seek(0, SeekOrigin.Begin);

            for (int i = 0; i < strContent.Length; i++)
            {
                if (strContent[i].Trim() == "\r\n")
                    continue;

                if (strContent[i].Trim() == "")
                    continue;

                streamWriter.WriteLine(strContent[i].Trim());
            }

            streamWriter.Flush();
            streamWriter.Close();
            fs.Close();
        }

        /// <summary>
        /// 解析ini文件
        /// </summary>
        /// <param name="isRead"></param>
        /// <param name="applicationName"></param>
        /// <param name="keyName"></param>
        /// <param name="defaultValue"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private static string IniCommon(bool isRead, string applicationName, string keyName, string defaultValue, string fileName)
        {
            string strSection = "[" + applicationName + "]";
            string strBuf;
            try
            {
                //a.文件不存在则创建
                if (!File.Exists(fileName))
                {
                    FileStream sr = File.Create(fileName);
                    sr.Close();
                }

                //读取INI文件
                using var stream = new StreamReader(fileName, Encoding.Default);
                strBuf = stream.ReadToEnd();
            }
            catch (Exception)
            {
                return defaultValue;
            }

            string[] rows = Split(strBuf, "\r\n");
            string oneRow;
            int i = 0;
            for (; i < rows.Length; i++)
            {
                oneRow = rows[i].Trim();

                //空行
                if (0 == oneRow.Length)
                    continue;

                //此行为注释
                if (';' == oneRow[0])
                    continue;

                //没找到
                if (strSection != oneRow)
                    continue;

                //找到了
                break;
            }

            //b.没找到对应的section，创建一节并创建属性
            if (i >= rows.Length)
            {
                AppendToFile(fileName, "\r\n" + strSection + "\r\n" + keyName + "=" + defaultValue);
                return defaultValue;
            }

            //找到section

            i += 1; //跳过section  

            //查找属性
            for (; i < rows.Length; i++)
            {
                oneRow = rows[i].Trim();

                //空行
                if (0 == oneRow.Length)
                    continue;

                //此行为注释
                if (';' == oneRow[0])
                    continue;

                //越界
                if ('[' == oneRow[0])
                {
                    break;
                }

                string[] strLeft = Split1(oneRow, "=");
                if (strLeft == null || strLeft.Length != 2)
                    continue;

                //找到属性
                if (strLeft[0].Trim() == keyName)
                {
                    //读
                    if (isRead)
                    {
                        //c.找到属性但没有值
                        if (0 == strLeft[1].Trim().Length)
                        {
                            //rows[i] = strLeft[0].Trim() + "=" + Default;
                            //WriteArray(FileName, rows);
                            return defaultValue;
                        }
                        //找到了
                        return strLeft[1].Trim();
                    }

                    //写
                    rows[i] = strLeft[0].Trim() + "=" + defaultValue;
                    WriteArray(fileName, rows);
                    return defaultValue;
                }
            }

            int bakIdxSection = i - 1;
            //d.没找到对应的属性,创建之并赋为默认
            rows[bakIdxSection] = rows[bakIdxSection] + "\r\n" + keyName + "=" + defaultValue;
            WriteArray(fileName, rows);
            return defaultValue;
        }

        #endregion

    }
}